/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package service

import (
	"did-service/bean/entity"
	"did-service/bean/model"
	"did-service/common/constant"
	"did-service/common/crypto/gm"
	"encoding/base64"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

type Contents model.Content

type Resource model.Resource

type EndpointUrl model.EndpointUrl

func (ds *DidService) GetResolve(did, versionId string) (Contents, error) {
	content, err := ds.didDocumentCommon(did, versionId, "0")
	return content, err
}

func (ds *DidService) GetDereference(didUrl string) (Contents, Resource, EndpointUrl, error) {
	// 解码
	decodeString, err := base64.URLEncoding.DecodeString(didUrl)
	if err != nil {
		return Contents{}, Resource{}, EndpointUrl{}, err
	}
	didUrls := string(decodeString)
	if strings.Contains(didUrls, "service") {
		endpointUrl := EndpointUrl{}
		endpointUrl.EndpointUrls = "https://localhost:8090/germ#request"
		return Contents{}, Resource{}, endpointUrl, nil
	}
	if strings.Contains(didUrls, "keys-") {
		//index := strings.Index(didUrls, "#")
		//did := didUrls[:index]
		documentKey := make([]entity.DidDocumentKey, 0)
		dcKErr := ds.engine.Where("key_id = ?", didUrls).Find(&documentKey)
		if dcKErr != nil {
			return Contents{}, Resource{}, EndpointUrl{}, dcKErr
		}
		resource := Resource{}
		resource.Resources.Id = documentKey[0].KeyId
		resource.Resources.Type = documentKey[0].Type
		resource.Resources.PublicKeyHex = documentKey[0].PubKey
		resource.Resources.PublicKey = gm.GetPubKeyBase64(documentKey[0].PubKey)
		return Contents{}, resource, EndpointUrl{}, nil
	}

	if !strings.Contains(didUrls, "#") {
		content, didErr := ds.didDocumentCommon(didUrls, "", "1")
		if didErr != nil {
			return Contents{}, Resource{}, EndpointUrl{}, didErr
		}
		return content, Resource{}, EndpointUrl{}, nil
	}
	return Contents{}, Resource{}, EndpointUrl{}, nil
}

func (ds *DidService) didDocumentCommon(did, versionId, term string) (Contents, error) {
	document := make([]entity.DidDocument, 0)
	dcErr := errors.New("程序异常")
	if term == "0" {
		dcErr = ds.engine.Where("version = ? and did = ? and status = ?", versionId, did, "1").Find(&document)
	} else {
		dcErr = ds.engine.Where("did = ? and status = ?", did, "1").Find(&document)
	}
	if dcErr != nil {
		return Contents{}, dcErr
	}
	if len(document) == 0 {
		return Contents{}, errors.New("document信息为空!")
	}

	documentKey := make([]entity.DidDocumentKey, 0)
	dcKErr := ds.engine.Where("did like concat('%', ?::varchar, '%')", did).Find(&documentKey)
	if dcKErr != nil {
		return Contents{}, dcKErr
	}
	if len(documentKey) == 0 {
		return Contents{}, errors.New("documentKey信息为空!")
	}

	publicKey := make([]model.PublicKey, 0)
	for _, d := range documentKey {
		key := model.PublicKey{}
		key.Id = d.KeyId
		key.Type = d.Type
		key.PublicKeyHex = d.PubKey
		publicKey = append(publicKey, key)
	}

	services := make([]model.Service, 0)
	service := model.Service{}
	service.Id = document[0].Did + constant.DefaultServiceResolveSubfix
	service.Type = constant.DefaultServiceResolveType
	service.ServiceEndpoint = constant.DefaultServiceResolveEndpoint
	services = append(services, service)

	proof := model.Proof{
		Type:           document[0].ProofType,
		Creator:        document[0].ProofCreator,
		SignatureValue: document[0].ProofSignature,
	}

	result := model.Document{
		Context:        constant.DefaultContext,
		Id:             document[0].Did,
		Version:        document[0].Version,
		Created:        document[0].CreatedTime.Format(constant.TimeLayout),
		Updated:        document[0].UpdatedTime.Format(constant.TimeLayout),
		PublicKey:      publicKey,
		Authentication: []string{document[0].AuthPubKey},
		Recovery:       []string{document[0].RecoveryPubKey},
		Service:        services,
		Proof:          proof,
	}

	content := Contents{}
	content.Document = result
	return content, nil
}

func (Con Contents) IsEmpty() bool {
	return reflect.DeepEqual(Con, Contents{})
}

func (Res Resource) IsEmpty() bool {
	return reflect.DeepEqual(Res, Resource{})
}

func (End EndpointUrl) IsEmpty() bool {
	return reflect.DeepEqual(End, EndpointUrl{})
}
